home *** CD-ROM | disk | FTP | other *** search
- /*
- * memory chunk low-level allocation routines
- *
- * Copyright 1992 by Gray Watson and the Antaire Corporation
- *
- * This file is part of the malloc-debug package.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library (see COPYING-LIB); if not, write to the
- * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * The author of the program may be contacted at gray.watson@antaire.com
- */
-
- /*
- * This file contains algorithm level routine for the heap. They handle the
- * manipulation and administration of chunks of memory.
- */
-
- #define MALLOC_DEBUG_DISABLE
-
- #include "malloc.h"
- #include "malloc_loc.h"
-
- #include "chunk.h"
- #include "chunk_loc.h"
- #include "compat.h"
- #include "conf.h"
- #include "dbg_values.h"
- #include "error.h"
- #include "error_val.h"
- #include "heap.h"
- #include "version.h"
-
- #if INCLUDE_RCS_IDS
- LOCAL char *rcs_id =
- "$Id: chunk.c,v 1.29 1993/04/05 22:29:52 gray Exp $";
- #endif
-
- /* checking information */
- #define MIN_FILE_LENGTH 3 /* min "[a-zA-Z].c" length */
- #define MAX_FILE_LENGTH 40 /* max __FILE__ length */
- #define MAX_LINE_NUMBER 10000 /* max __LINE__ value */
-
- #define FREE_COLUMN 5 /* for dump_free formatting */
- #define FREE_CHAR '\305' /* to blank free space with */
-
- /* free lists of bblocks and dblocks */
- LOCAL bblock_t *free_bblock[LARGEST_BLOCK + 1];
- LOCAL dblock_t *free_dblock[BASIC_BLOCK];
-
- /* administrative structures */
- LOCAL bblock_adm_t *bblock_adm_head = NULL; /* pointer to 1st bb_admin */
- LOCAL bblock_adm_t *bblock_adm_tail = NULL; /* pointer to last bb_admin */
-
- /* user information shifts for display purposes */
- LOCAL int pnt_below_adm = 0; /* add to pnt for display */
- LOCAL int pnt_total_adm = 0; /* total adm per pointer */
-
- /* memory stats */
- LOCAL long alloc_current = 0; /* current memory usage */
- LOCAL long alloc_cur_given = 0; /* current mem given */
- LOCAL long alloc_maximum = 0; /* maximum memory usage */
- LOCAL long alloc_max_given = 0; /* maximum mem given */
- LOCAL long alloc_total = 0; /* total allocation */
- LOCAL long alloc_one_max = 0; /* maximum at once */
- LOCAL int free_space_count = 0; /* count the free bytes */
-
- /* pointer stats */
- LOCAL long alloc_cur_pnts = 0; /* current pointers */
- LOCAL long alloc_max_pnts = 0; /* maximum pointers */
- LOCAL long alloc_tot_pnts = 0; /* current pointers */
-
- /* admin counts */
- LOCAL int bblock_adm_count = 0; /* count of bblock_admin */
- LOCAL int dblock_adm_count = 0; /* count of dblock_admin */
- LOCAL int bblock_count = 0; /* count of basic-blocks */
- LOCAL int dblock_count = 0; /* count of divided-blocks */
-
- /* alloc counts */
- EXPORT int _calloc_count = 0; /* # callocs, done in alloc */
- LOCAL int free_count = 0; /* count the frees */
- LOCAL int malloc_count = 0; /* count the mallocs */
- LOCAL int realloc_count = 0; /* count the reallocs */
-
- /************************* fence-post error functions ************************/
-
- /*
- * check PNT of SIZE for fence-post magic numbers, returns ERROR or NOERROR
- */
- LOCAL int fence_read(const char * file, const unsigned int line,
- char * pnt, unsigned int size)
- {
- long top, *longp;
-
- /*
- * write magic numbers into block in bottom of allocation
- *
- * WARNING: assuming a word-boundary here
- */
- for (longp = (long *)pnt; longp < (long *)(pnt + FENCE_BOTTOM); longp++)
- if (*longp != FENCE_MAGIC_BASE) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("under fence on pointer '%#lx' alloced in '%s:%u'",
- CHUNK_TO_USER(pnt), file, line);
- malloc_errno = MALLOC_UNDER_FENCE;
- _malloc_perror("fence_read");
- return ERROR;
- }
-
- /*
- * write magic numbers into block in top of allocation
- *
- * WARNING: not guaranteed a word-boundary here
- */
- for (longp = (long *)(pnt + size - FENCE_TOP); longp < (long *)(pnt + size);
- longp++) {
- bcopy(longp, &top, sizeof(long));
- if (top != FENCE_MAGIC_TOP) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("over fence on pointer '%#lx' alloced in '%s:%u'",
- CHUNK_TO_USER(pnt), file, line);
- malloc_errno = MALLOC_OVER_FENCE;
- _malloc_perror("fence_read");
- return ERROR;
- }
- }
-
- return NOERROR;
- }
-
- /*
- * load PNT of SIZE bytes with fence-post magic numbers
- */
- LOCAL void fence_write(char * pnt, unsigned int size)
- {
- long top = FENCE_MAGIC_TOP;
- long *longp;
-
- /* write magic numbers into block in bottom of allocation */
- for (longp = (long *)pnt; longp < (long *)(pnt + FENCE_BOTTOM); longp++)
- *longp = FENCE_MAGIC_BASE;
-
- /* write magic numbers into block in top of allocation */
- /* WARNING: not guaranteed a word-boundary here */
- for (longp = (long *)(pnt + size - FENCE_TOP); longp < (long *)(pnt + size);
- longp++)
- bcopy(&top, longp, sizeof(long));
- }
-
- /************************** administration functions *************************/
-
- /*
- * startup the low level malloc routines
- */
- EXPORT int _chunk_startup(void)
- {
- int binc;
-
- /* verify some conditions */
- if (BB_PER_ADMIN <= 2
- || sizeof(bblock_adm_t) > BLOCK_SIZE
- || DB_PER_ADMIN < (1 << (BASIC_BLOCK - SMALLEST_BLOCK))
- || sizeof(dblock_adm_t) > BLOCK_SIZE
- || SMALLEST_BLOCK < ALLOCATION_ALIGNMENT_IN_BITS) {
- malloc_errno = MALLOC_BAD_SETUP;
- _malloc_perror("_chunk_startup");
- return ERROR;
- }
-
- /* align the base pointer */
- if (_heap_align_base(BLOCK_SIZE) == MALLOC_ERROR) {
- malloc_errno = MALLOC_BAD_SETUP;
- _malloc_perror("_chunk_startup");
- return ERROR;
- }
-
- /* initialize free bins */
- for (binc = 0; binc <= LARGEST_BLOCK; binc++)
- free_bblock[binc] = NULL;
- for (binc = 0; binc < BASIC_BLOCK; binc++)
- free_dblock[binc] = NULL;
-
- /* assign value to add to pointers when displaying */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
- pnt_below_adm = FENCE_BOTTOM;
- pnt_total_adm = FENCE_OVERHEAD;
- }
- else {
- pnt_below_adm = 0;
- pnt_total_adm = 0;
- }
-
- return NOERROR;
- }
-
- /*
- * return the number of bits in number SIZE
- */
- LOCAL int num_bits(unsigned int size)
- {
- unsigned int tmp = size;
- int bitc;
-
- #if ALLOW_ALLOC_ZERO_SIZE == 0
- if (size == 0) {
- malloc_errno = MALLOC_BAD_SIZE;
- _malloc_perror("num_bits");
- return ERROR;
- }
- #endif
-
- /* shift right until 0, 2 ^ 0 == 1 */
- for (bitc = -1; tmp > 0; bitc++)
- tmp >>= 1;
-
- /* are we not a base 2 number? */
- if (size > (1 << bitc))
- bitc++;
-
- return bitc;
- }
-
- /*
- * "allocate" another bblock administrative block
- * NOTE: some logistic problems with getting from free list
- */
- LOCAL bblock_adm_t *get_bblock_admin(void)
- {
- bblock_adm_t *new;
- bblock_t *bblockp;
-
- bblock_adm_count++;
- bblock_count++;
-
- /* get some more space for a bblock_admin structure */
- new = (bblock_adm_t *)_heap_alloc(BLOCK_SIZE);
- if (new == (bblock_adm_t *)HEAP_ALLOC_ERROR)
- return NULL;
-
- /* do we need to print admin info? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("new bblock admin alloced for another %d admin slots",
- BB_PER_ADMIN);
-
- /*
- * initialize the new bblock_admin block
- */
- new->ba_magic1 = CHUNK_MAGIC_BASE;
- if (bblock_adm_tail == NULL)
- new->ba_count = 0;
- else
- new->ba_count = bblock_adm_tail->ba_count + BB_PER_ADMIN;
-
- /* initialize the bblocks in the bblock_admin */
- for (bblockp = new->ba_block; bblockp < new->ba_block + BB_PER_ADMIN;
- bblockp++)
- bblockp->bb_flags = 0;
-
- new->ba_next = NULL;
- new->ba_magic2 = CHUNK_MAGIC_TOP;
-
- /*
- * continue bblock_admin linked-list
- */
- if (bblock_adm_tail == NULL)
- bblock_adm_head = new;
- else
- bblock_adm_tail->ba_next = new;
- bblock_adm_tail = new;
-
- return new;
- }
-
- /*
- * get MANY of bblocks, return a pointer to the first one
- */
- LOCAL bblock_t *get_bblocks(int bitc)
- {
- static int free_slots = 0; /* free slots in last bb_admin */
- int newc, mark;
- bblock_adm_t *bblock_admp;
- bblock_t *bblockp;
-
- if (bitc < BASIC_BLOCK) {
- malloc_errno = MALLOC_BAD_SIZE;
- _malloc_perror("get_bblocks");
- return NULL;
- }
-
- /* do we need to print admin info? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("need bblocks for %d bytes or %d bits", 1 << bitc, bitc);
-
- /* is there anything on the free list? */
- bblockp = free_bblock[bitc];
- if (bblockp != NULL) {
- free_bblock[bitc] = bblockp->bb_next;
- free_space_count -= 1 << bitc;
- return bblockp;
- }
-
- bblock_count += 1 << (bitc - BASIC_BLOCK);
-
- /* point at first free bblock entry (may be out of range) */
- bblock_admp = bblock_adm_tail;
- mark = BB_PER_ADMIN - free_slots;
-
- /* loop until we have enough slots */
- for (newc = 0; free_slots < 1 << (bitc - BASIC_BLOCK); newc++) {
- if (get_bblock_admin() == NULL)
- return NULL;
-
- /* do we need to move to the next bblock admin? */
- if (mark == BB_PER_ADMIN) {
- if (bblock_admp == NULL)
- bblock_admp = bblock_adm_tail;
- else
- bblock_admp = bblock_admp->ba_next;
- mark = 0;
- }
-
- /* write a bblock entry for the bblock admin */
- bblockp = &bblock_admp->ba_block[mark];
-
- bblockp->bb_flags = BBLOCK_ADMIN;
- bblockp->bb_count = bblock_adm_tail->ba_count;
- bblockp->bb_adminp = bblock_adm_tail;
-
- /* add one to mark to pass by bblock admin header */
- mark++;
-
- /* adjust free_slot count for addition of new bblock admin */
- free_slots += BB_PER_ADMIN - 1;
- }
-
- /* do we need to move to the next bblock admin? */
- if (mark == BB_PER_ADMIN) {
- bblock_admp = bblock_admp->ba_next;
- mark = 0;
- }
-
- /* adjust free_slot count for the allocation */
- free_slots -= 1 << (bitc - BASIC_BLOCK);
-
- return &bblock_admp->ba_block[mark];
- }
-
- /*
- * get MANY of contiguous dblock administrative slots
- */
- LOCAL dblock_t *get_dblock_admin(int many)
- {
- static int free_slots = 0;
- static dblock_adm_t *dblock_admp;
- dblock_t *dblockp;
- bblock_t *bblockp;
-
- /* do we need to print admin info? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("need %d dblock slots", many);
-
- /* do we have enough right now */
- if (free_slots >= many) {
- free_slots -= many;
- return &dblock_admp->da_block[DB_PER_ADMIN - (free_slots + many)];
- }
-
- /*
- * allocate a new bblock of dblock admin slots, should use free list
- */
- bblockp = get_bblocks(BASIC_BLOCK);
- if (bblockp == NULL)
- return NULL;
-
- dblock_adm_count++;
-
- /* allocate the block if needed */
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED))
- dblock_admp = (dblock_adm_t *)bblockp->bb_mem;
- else
- dblock_admp = (dblock_adm_t *)_heap_alloc(BLOCK_SIZE);
- if (dblock_admp == (dblock_adm_t *)HEAP_ALLOC_ERROR)
- return NULL;
-
- bblockp->bb_flags = BBLOCK_DBLOCK_ADMIN;
- bblockp->bb_slotp = dblock_admp;
-
- /* do we need to print admin info? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("opened another %d dblock slots", DB_PER_ADMIN);
-
- dblock_admp->da_magic1 = CHUNK_MAGIC_BASE;
-
- /* initialize the db_slots */
- for (dblockp = dblock_admp->da_block;
- dblockp < dblock_admp->da_block + DB_PER_ADMIN; dblockp++) {
- dblockp->db_bblock = NULL;
- dblockp->db_next = NULL;
- }
-
- dblock_admp->da_magic2 = CHUNK_MAGIC_TOP;
-
- free_slots = DB_PER_ADMIN - many;
-
- return dblock_admp->da_block;
- }
-
- /*
- * get a dblock of 1<<BITC sized chunks, also asked for the slot memory
- */
- LOCAL char *get_dblock(int bitc, dblock_t ** admp)
- {
- bblock_t *bblockp;
- dblock_t *dblockp;
- char *mem;
-
- /* is there anything on the dblock free list? */
- dblockp = free_dblock[bitc];
- if (dblockp != NULL) {
- free_dblock[bitc] = dblockp->db_next;
- free_space_count -= 1 << bitc;
-
- *admp = dblockp;
-
- /* find pointer to memory chunk */
- mem = dblockp->db_bblock->bb_mem +
- (dblockp - dblockp->db_bblock->bb_dblock) * (1 << bitc);
-
- /* do we need to print admin info? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("found a %d byte dblock entry", 1 << bitc);
-
- return mem;
- }
-
- /* do we need to print admin info? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("need to create a dblock for %dx %d byte blocks",
- 1 << (BASIC_BLOCK - bitc), 1 << bitc);
-
- /* get some dblock admin slots */
- dblockp = get_dblock_admin(1 << (BASIC_BLOCK - bitc));
- if (dblockp == NULL)
- return NULL;
- *admp = dblockp;
-
- dblock_count++;
-
- /* get a bblock from free list */
- bblockp = get_bblocks(BASIC_BLOCK);
- if (bblockp == NULL)
- return NULL;
-
- /* allocate the block if needed */
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED))
- mem = bblockp->bb_mem;
- else {
- mem = _heap_alloc(BLOCK_SIZE);
- if (mem == HEAP_ALLOC_ERROR)
- return NULL;
- bblockp->bb_mem = mem;
- }
-
- /* setup bblock information */
- bblockp->bb_flags = BBLOCK_DBLOCK;
- bblockp->bb_bitc = bitc;
- bblockp->bb_dblock = dblockp;
-
- /* add the rest to the free list (has to be at least 1 other dblock) */
- free_dblock[bitc] = ++dblockp;
- free_space_count += 1 << bitc;
-
- for (; dblockp < *admp + (1 << (BASIC_BLOCK - bitc)) - 1; dblockp++) {
- dblockp->db_next = dblockp + 1;
- dblockp->db_bblock = bblockp;
- free_space_count += 1 << bitc;
- }
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
- (void)memset(mem + (1 << bitc), FREE_CHAR, BLOCK_SIZE - (1 << bitc));
-
- /* last one points to NULL */
- dblockp->db_next = NULL;
- dblockp->db_bblock = bblockp;
-
- return mem;
- }
-
- /*
- * find the bblock entry for PNT, return bblock admin in *BB_ADMIN (if != NULL)
- * and return the block number in BLOCK_NUM (if non NULL)
- */
- LOCAL bblock_t *find_bblock(char * pnt, int * block_num,
- bblock_adm_t ** bb_admin)
- {
- int bblockc;
- bblock_adm_t *bblock_admp;
-
- if (pnt == NULL) {
- malloc_errno = MALLOC_POINTER_NULL;
- return NULL;
- }
-
- /*
- * check validity of the pointer
- */
- if (! IS_IN_HEAP(pnt)) {
- malloc_errno = MALLOC_POINTER_NOT_IN_HEAP;
- return NULL;
- }
-
- /* find which block it is in */
- bblockc = WHICH_BLOCK(pnt);
-
- /* do we need to return the block number */
- if (block_num != NULL)
- *block_num = bblockc;
-
- /* find right bblock admin */
- for (bblock_admp = bblock_adm_head; bblock_admp != NULL;
- bblock_admp = bblock_admp->ba_next) {
- if (bblockc < BB_PER_ADMIN)
- break;
-
- bblockc -= BB_PER_ADMIN;
- }
-
- if (bblock_admp == NULL) {
- malloc_errno = MALLOC_POINTER_NOT_FOUND;
- return NULL;
- }
-
- /* should we return bblock admin info? */
- if (bb_admin != NULL)
- *bb_admin = bblock_admp;
-
- return &bblock_admp->ba_block[bblockc];
- }
-
- /*
- * log the heap structure plus information on the blocks if necessary
- */
- LOCAL void log_heap_map(void)
- {
- bblock_adm_t *bblock_admp;
- char line[BB_PER_ADMIN + 10];
- int linec, bblockc, bb_adminc;
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("logging heap map information");
-
- _malloc_message("heap-base = %#lx, heap-end = %#lx, size = %ld bytes",
- _heap_base, _heap_last, HEAP_SIZE);
-
- for (bb_adminc = 0, bblock_admp = bblock_adm_head; bblock_admp != NULL;
- bb_adminc++, bblock_admp = bblock_admp->ba_next) {
- linec = 0;
-
- for (bblockc = 0; bblockc < BB_PER_ADMIN; bblockc++) {
- bblock_t *bblockp = &bblock_admp->ba_block[bblockc];
-
- if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED)) {
- line[linec++] = '_';
- continue;
- }
-
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
- line[linec++] = 'S';
- continue;
- }
-
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_USER)) {
- line[linec++] = 'U';
- continue;
- }
-
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_ADMIN)) {
- line[linec++] = 'A';
- continue;
- }
-
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
- line[linec++] = 'd';
- continue;
- }
-
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK_ADMIN)) {
- line[linec++] = 'a';
- continue;
- }
-
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_FREE)) {
- line[linec++] = 'F';
- continue;
- }
- }
-
- /* dumping a line to the logfile */
- if (linec > 0) {
- line[linec] = NULLC;
- _malloc_message("S%d:%s", bb_adminc, line);
- }
- }
-
- /* if we are not logging blocks then leave */
- if (! BIT_IS_SET(_malloc_debug, DEBUG_LOG_BLOCKS))
- return;
-
- for (bb_adminc = 0, bblock_admp = bblock_adm_head; bblock_admp != NULL;
- bb_adminc++, bblock_admp = bblock_admp->ba_next) {
-
- for (bblockc = 0; bblockc < BB_PER_ADMIN; bblockc++) {
- bblock_t *bblockp = &bblock_admp->ba_block[bblockc];
-
- if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED)) {
- _malloc_message("%d: not-allocated block",
- bb_adminc * BB_PER_ADMIN + bblockc);
- /* quit after the first non-allocated is found */
- break;
- }
-
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
- _malloc_message("%d: start-of-user block: %d bytes from '%s:%u'",
- bb_adminc * BB_PER_ADMIN + bblockc,
- bblockp->bb_size, bblockp->bb_file, bblockp->bb_line);
- continue;
- }
-
- if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_USER)) {
- _malloc_message("%d: user continuation block",
- bb_adminc * BB_PER_ADMIN + bblockc);
- continue;
- }
-
- if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_ADMIN)) {
- _malloc_message("%d: administration block",
- bb_adminc * BB_PER_ADMIN + bblockc);
- continue;
- }
-
- if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_DBLOCK)) {
- _malloc_message("%d: dblock block",
- bb_adminc * BB_PER_ADMIN + bblockc);
- continue;
- }
-
- if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags,
- BBLOCK_DBLOCK_ADMIN)) {
- _malloc_message("%d: dblock-admin block",
- bb_adminc * BB_PER_ADMIN + bblockc);
- continue;
- }
-
- if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_FREE)) {
- _malloc_message("%d: free block",
- bb_adminc * BB_PER_ADMIN + bblockc);
- continue;
- }
- }
- }
- }
-
- /*
- * run extensive tests on the entire heap depending on TYPE
- */
- EXPORT int _chunk_heap_check(void)
- {
- bblock_adm_t *this, *last_admp;
- bblock_t *bblockp, *bblistp, *last_bblockp;
- dblock_t *dblockp;
- int undef = 0, start = 0;
- char *bytep;
- char *mem;
- int bitc, dblockc = 0, bblockc = 0, freec = 0;
- int bbc = 0, len;
- int free_bblockc[LARGEST_BLOCK + 1];
- int free_dblockc[BASIC_BLOCK];
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("checking heap");
-
- /* if the heap is empty then no need to check anything */
- if (bblock_adm_head == NULL)
- return NOERROR;
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
-
- /* count the bblock free lists */
- for (bitc = 0; bitc < LARGEST_BLOCK + 1; bitc++) {
- free_bblockc[bitc] = 0;
-
- /* parse bblock free list doing minimal pointer checking */
- for (bblockp = free_bblock[bitc]; bblockp != NULL;
- bblockp = bblockp->bb_next, free_bblockc[bitc]++)
- if (bblockp->bb_next != NULL && ! IS_IN_HEAP(bblockp->bb_next)) {
- malloc_errno = MALLOC_BAD_FREE_LIST;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- }
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
-
- /* count the dblock free lists */
- for (bitc = 0; bitc < BASIC_BLOCK; bitc++) {
- free_dblockc[bitc] = 0;
-
- /* parse dblock free list doing minimal pointer checking */
- for (dblockp = free_dblock[bitc]; dblockp != NULL;
- dblockp = dblockp->db_next, free_dblockc[bitc]++)
- if (dblockp->db_next != NULL && ! IS_IN_HEAP(dblockp->db_next)) {
- malloc_errno = MALLOC_BAD_FREE_LIST;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- }
- }
- }
-
- /* start pointers */
- this = bblock_adm_head;
- last_admp = NULL;
- last_bblockp = NULL;
-
- /* test admin pointer validity */
- if (! IS_IN_HEAP(this)) {
- malloc_errno = MALLOC_BAD_ADMINP;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* test structure validity */
- if (this->ba_magic1 != CHUNK_MAGIC_BASE
- || this->ba_magic2 != CHUNK_MAGIC_TOP) {
- malloc_errno = MALLOC_BAD_ADMIN_MAGIC;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* verify count value */
- if (this->ba_count != bbc) {
- malloc_errno = MALLOC_BAD_ADMIN_COUNT;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* check out the basic blocks */
- for (bblockp = this->ba_block;; last_bblockp = bblockp++) {
-
- /* are we at the end of the bb_admin section */
- if (bblockp >= this->ba_block + BB_PER_ADMIN) {
- this = this->ba_next;
- bbc += BB_PER_ADMIN;
-
- /* are we done? */
- if (this == NULL)
- break;
-
- /* test admin pointer validity */
- if (! IS_IN_HEAP(this)) {
- malloc_errno = MALLOC_BAD_ADMINP;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* test structure validity */
- if (this->ba_magic1 != CHUNK_MAGIC_BASE
- || this->ba_magic2 != CHUNK_MAGIC_TOP) {
- malloc_errno = MALLOC_BAD_ADMIN_MAGIC;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* verify count value */
- if (this->ba_count != bbc) {
- malloc_errno = MALLOC_BAD_ADMIN_COUNT;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- bblockp = this->ba_block;
- }
-
- /* check for no-allocation */
- if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED)) {
- undef = 1;
- continue;
- }
-
- /* we better not have seen a not-allocated block before */
- if (undef == 1) {
- malloc_errno = MALLOC_BAD_BLOCK_ORDER;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- start = 0;
-
- /*
- * check for different types
- */
- switch (bblockp->bb_flags) {
-
- /* check a starting user-block */
- case BBLOCK_START_USER:
-
- /* check X blocks in a row */
- if (bblockc != 0) {
- malloc_errno = MALLOC_USER_NON_CONTIG;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* mark the size in bits */
- bitc = num_bits(bblockp->bb_size);
- if (bitc == ERROR)
- return ERROR;
- bblockc = 1 << (bitc - BASIC_BLOCK);
- start = 1;
-
- /* check fence-posts for memory chunk */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
- mem = BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block));
- if (fence_read(bblockp->bb_file, bblockp->bb_line,
- mem, bblockp->bb_size) != NOERROR)
- return ERROR;
- }
-
- /* NOTE: NO BREAK HERE ON PURPOSE */
-
- case BBLOCK_USER:
-
- /* check line number */
- if (bblockp->bb_line > MAX_LINE_NUMBER) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad line number on pointer alloced in '%s:%u'",
- bblockp->bb_file, bblockp->bb_line);
- malloc_errno = MALLOC_BAD_LINE;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* check out size, BLOCK_SIZE / 2 == 512 when dblock allocs take over */
- if (bblockp->bb_size <= BLOCK_SIZE / 2
- || bblockp->bb_size > (1 << LARGEST_BLOCK)) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad size on pointer alloced in '%s:%u'",
- bblockp->bb_file, bblockp->bb_line);
- malloc_errno = MALLOC_BAD_SIZE;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* check file pointer */
- if (bblockp->bb_file == NULL) {
- len = strlen(bblockp->bb_file);
- if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
- malloc_errno = MALLOC_BAD_FILEP;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- }
-
- /* check X blocks in a row */
- if (bblockc == 0) {
- malloc_errno = MALLOC_USER_NON_CONTIG;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- else
- if (start == 0
- && (last_bblockp == NULL
- || (last_bblockp->bb_flags != BBLOCK_START_USER &&
- last_bblockp->bb_flags != BBLOCK_USER)
- || bblockp->bb_file != last_bblockp->bb_file
- || bblockp->bb_line != last_bblockp->bb_line
- || bblockp->bb_size != last_bblockp->bb_size)) {
- malloc_errno = MALLOC_USER_NON_CONTIG;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- bblockc--;
-
- /* NOTE: we should check above the allocated space if alloc_blank on */
-
- break;
-
- case BBLOCK_ADMIN:
-
- /* check the bblock_admin linked-list */
- if ((last_admp == NULL && bblockp->bb_adminp != bblock_adm_head)
- || (last_admp != NULL && last_admp->ba_next != bblockp->bb_adminp)) {
- malloc_errno = MALLOC_BAD_BLOCK_ADMINP;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- last_admp = bblockp->bb_adminp;
-
- /* check count against admin count */
- if (bblockp->bb_count != bblockp->bb_adminp->ba_count) {
- malloc_errno = MALLOC_BAD_BLOCK_ADMINC;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- break;
-
- case BBLOCK_DBLOCK:
-
- /* check out bitc */
- if (bblockp->bb_bitc >= BASIC_BLOCK) {
- malloc_errno = MALLOC_BAD_DBLOCK_SIZE;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* check out dblock pointer */
- if (! IS_IN_HEAP(bblockp->bb_dblock)) {
- malloc_errno = MALLOC_BAD_DBLOCK_POINTER;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* verify mem pointer */
- if (bblockp->bb_mem !=
- BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block))) {
- malloc_errno = MALLOC_BAD_DBLOCK_MEM;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* check dblock entry very closely if necessary */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
- for (dblockc = 0, dblockp = bblockp->bb_dblock;
- dblockp < bblockp->bb_dblock +
- (1 << (BASIC_BLOCK - bblockp->bb_bitc));
- dblockc++, dblockp++) {
-
- /* check out dblock entry to see if it is not free */
- if (dblockp->db_next == NULL || IS_IN_HEAP(dblockp->db_next)) {
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
- dblock_t *dblistp;
-
- /* find the free block in the free list */
- for (dblistp = free_dblock[bblockp->bb_bitc]; dblistp != NULL;
- dblistp = dblistp->db_next)
- if (dblistp == dblockp)
- break;
-
- /* did we find it? */
- if (dblistp == NULL) {
- malloc_errno = MALLOC_BAD_FREE_LIST;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- free_dblockc[bblockp->bb_bitc]--;
- }
-
- continue;
- }
-
- /*
- * check out size, better be less than BLOCK_SIZE / 2
- * I have to check this twice :-(
- */
- if (dblockp->db_size > BLOCK_SIZE / 2) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad size on pointer alloced in '%s:%u'",
- dblockp->db_file, dblockp->db_line);
- malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)
- && BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DB_FENCE)) {
- mem = bblockp->bb_mem + dblockc * (1 << bblockp->bb_bitc);
- if (fence_read(dblockp->db_file, dblockp->db_line,
- mem, dblockp->db_size) != NOERROR)
- return ERROR;
- }
- }
- }
- break;
-
- case BBLOCK_DBLOCK_ADMIN:
-
- /* check out dblock pointer */
- if (! IS_IN_HEAP(bblockp->bb_slotp)) {
- malloc_errno = MALLOC_BAD_DBADMIN_POINTER;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* verify magic numbers */
- if (bblockp->bb_slotp->da_magic1 != CHUNK_MAGIC_BASE
- || bblockp->bb_slotp->da_magic2 != CHUNK_MAGIC_TOP) {
- malloc_errno = MALLOC_BAD_DBADMIN_MAGIC;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* check out each dblock_admin struct? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
- for (dblockp = bblockp->bb_slotp->da_block;
- dblockp < bblockp->bb_slotp->da_block + DB_PER_ADMIN; dblockp++) {
-
- /* verify if we have a good bblock pointer and good back pointer */
- if (dblockp->db_bblock == NULL && dblockp->db_next == NULL)
- continue;
-
- /* check out dblock pointer and next pointer (if free) */
- if (dblockp->db_next == NULL || IS_IN_HEAP(dblockp->db_next)) {
-
- /* find pointer to memory chunk */
- mem = dblockp->db_bblock->bb_mem +
- (dblockp - dblockp->db_bblock->bb_dblock) *
- (1 << dblockp->db_bblock->bb_bitc);
-
- /* should we verify that we have a block of FREE_CHAR? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FREE)
- && BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
- for (bytep = (char *)mem;
- bytep < (char *)mem + (1 << dblockp->db_bblock->bb_bitc);
- bytep++)
- if (*bytep != FREE_CHAR) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad free memory at '%#lx'", bytep);
- malloc_errno = MALLOC_FREE_NON_BLANK;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- continue;
- }
-
- /* check out size, better be less than BLOCK_SIZE / 2 */
- if (dblockp->db_size > BLOCK_SIZE / 2) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad size on pointer alloced in '%s:%u'",
- dblockp->db_file, dblockp->db_line);
- malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* check line number */
- if (dblockp->db_line > MAX_LINE_NUMBER) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad line number on pointer alloced in '%s:%u'",
- dblockp->db_file, dblockp->db_line);
- malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- len = strlen(dblockp->db_file);
- if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
- malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- }
- }
- break;
-
- case BBLOCK_FREE:
-
- /* NOTE: check out free_lists, depending on debug value? */
-
- /* check out bitc which is the free-lists size */
- if (bblockp->bb_bitc < BASIC_BLOCK
- || bblockp->bb_bitc > LARGEST_BLOCK) {
- malloc_errno = MALLOC_BAD_SIZE;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* verify linked list pointer */
- if (bblockp->bb_next != NULL && ! IS_IN_HEAP(bblockp->bb_next)) {
- malloc_errno = MALLOC_BAD_FREE_LIST;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* verify mem pointer */
- if (bblockp->bb_mem !=
- BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block))) {
- malloc_errno = MALLOC_BAD_FREE_MEM;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- /* check X blocks in a row */
- if (freec == 0) {
- freec = 1 << (bblockp->bb_bitc - BASIC_BLOCK);
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
-
- /* find the free block in the free list */
- for (bblistp = free_bblock[bblockp->bb_bitc]; bblistp != NULL;
- bblistp = bblistp->bb_next)
- if (bblistp == bblockp)
- break;
-
- /* did we find it? */
- if (bblistp == NULL) {
- malloc_errno = MALLOC_BAD_FREE_LIST;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- free_bblockc[bblockp->bb_bitc]--;
- }
- }
- else
- if (last_bblockp == NULL || last_bblockp->bb_flags != BBLOCK_FREE
- || bblockp->bb_bitc != last_bblockp->bb_bitc) {
- malloc_errno = MALLOC_FREE_NON_CONTIG;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- freec--;
-
- /* should we verify that we have a block of FREE_CHAR? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FREE)
- && BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
- for (bytep = (char *)bblockp->bb_mem;
- bytep < (char *)bblockp->bb_mem + BLOCK_SIZE; bytep++)
- if (*bytep != FREE_CHAR) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad free memory at '%#lx'", bytep);
- malloc_errno = MALLOC_FREE_NON_BLANK;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- break;
-
- default:
- malloc_errno = MALLOC_BAD_FLAG;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- break;
- }
- }
-
- /*
- * any left over contiguous counters?
- */
- if (bblockc > 0) {
- malloc_errno = MALLOC_USER_NON_CONTIG;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- if (freec > 0) {
- malloc_errno = MALLOC_FREE_NON_CONTIG;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
-
- /* any free bblock entries not accounted for? */
- for (bitc = 0; bitc < LARGEST_BLOCK + 1; bitc++)
- if (free_bblockc[bitc] != 0) {
- malloc_errno = MALLOC_BAD_FREE_LIST;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
- /* any free dblock entries not accounted for? */
- for (bitc = 0; bitc < BASIC_BLOCK; bitc++)
- if (free_dblockc[bitc] != 0) {
- malloc_errno = MALLOC_BAD_FREE_LIST;
- _malloc_perror("_chunk_heap_check");
- return ERROR;
- }
- }
- }
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_HEAP_CHECK_MAP))
- log_heap_map();
-
- return NOERROR;
- }
-
- /*
- * run extensive tests on PNT from FUNC. test PNT HOW_MUCH of MIN_SIZE
- * (or 0 if unknown). returns [NO]ERROR
- */
- EXPORT int _chunk_pnt_check(const char * func, char * pnt,
- const int check, int min_size)
- {
- bblock_t *bblockp;
- dblock_t *dblockp;
- int len, diff;
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("checking pointer '%#lx'", pnt);
-
- /* adjust the pointer down if fence-posting */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
- pnt -= FENCE_BOTTOM;
- if (min_size != 0)
- min_size += FENCE_OVERHEAD;
- }
-
- /* find which block it is in */
- bblockp = find_bblock(pnt, NULL, NULL);
- if (bblockp == NULL) {
- if (check == CHUNK_PNT_LOOSE) {
- /* the pointer might not be the heap or might be NULL */
- malloc_errno = 0;
- return NOERROR;
- }
- else {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", pnt);
- _malloc_perror("find_bblock");
- return ERROR;
- }
- }
-
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
- /* on a mini-block boundary? */
- diff = (pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc);
- if (diff != 0) {
- if (check == CHUNK_PNT_LOOSE) {
- if (min_size != 0)
- min_size += diff;
- pnt -= diff;
- }
- else {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_ON_BLOCK;
- _malloc_perror(func);
- return ERROR;
- }
- }
-
- /* find correct dblockp */
- dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
- (1 << bblockp->bb_bitc);
-
- if (dblockp->db_bblock == bblockp) {
- /* NOTE: we should run through free list here */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_ALREADY_FREE;
- _malloc_perror(func);
- return ERROR;
- }
-
- /* check line number */
- if (dblockp->db_line > MAX_LINE_NUMBER) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad line number on pointer '%#lx' alloced in '%s:%u'",
- CHUNK_TO_USER(pnt), dblockp->db_file,
- dblockp->db_line);
- malloc_errno = MALLOC_BAD_LINE;
- _malloc_perror(func);
- return ERROR;
- }
-
- /* check out size, BLOCK_SIZE / 2 == 512 when dblock allocs take over */
- if (dblockp->db_size > BLOCK_SIZE / 2) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad size on pointer '%#lx' alloced in '%s:%u'",
- CHUNK_TO_USER(pnt), dblockp->db_file,
- dblockp->db_line);
- malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
- _malloc_perror(func);
- return ERROR;
- }
-
- if (min_size != 0 && dblockp->db_size < min_size) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("not enough space in pointer '%#lx' alloced in "
- "'%s:%u'",
- CHUNK_TO_USER(pnt), dblockp->db_file,
- dblockp->db_line);
- malloc_errno = MALLOC_WOULD_OVERWRITE;
- _malloc_perror(func);
- return ERROR;
- }
-
- /* check file pointer */
- if (dblockp->db_file == NULL) {
- len = strlen(dblockp->db_file);
- if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad file-name on pointer '%#lx' alloced in '%s:%u'",
- CHUNK_TO_USER(pnt), dblockp->db_file,
- dblockp->db_line);
- malloc_errno = MALLOC_BAD_FILEP;
- _malloc_perror(func);
- return ERROR;
- }
- }
-
- /* check out the fence-posts */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
- if (fence_read(dblockp->db_file, dblockp->db_line,
- pnt, dblockp->db_size) != NOERROR)
- return ERROR;
-
- return NOERROR;
- }
-
- /* on a block boundary? */
- if (! ON_BLOCK(pnt)) {
- if (check == CHUNK_PNT_LOOSE) {
- /*
- * normalize size and pointer to nearest block.
- *
- * NOTE: we really need to back-track up the block list to find the
- * starting user block to test things.
- */
- diff = pnt - BLOCK_POINTER(WHICH_BLOCK(pnt));
- pnt -= diff;
- if (min_size != 0)
- min_size += diff;
- }
- else {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_ON_BLOCK;
- _malloc_perror(func);
- return ERROR;
- }
- }
-
- /* are we on a normal block */
- if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)
- && ! (check == CHUNK_PNT_LOOSE
- && BIT_IS_SET(bblockp->bb_flags, BBLOCK_USER))) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_START_USER;
- _malloc_perror(func);
- return ERROR;
- }
-
- /* check line number */
- if (bblockp->bb_line > MAX_LINE_NUMBER) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad line number on pointer '%#lx' alloced in '%s:%u'",
- CHUNK_TO_USER(pnt), bblockp->bb_file, bblockp->bb_line);
- malloc_errno = MALLOC_BAD_LINE;
- _malloc_perror(func);
- return ERROR;
- }
-
- /* check out size, BLOCK_SIZE / 2 == 512 when dblock allocs take over */
- if (bblockp->bb_size <= BLOCK_SIZE / 2
- || bblockp->bb_size > (1 << LARGEST_BLOCK)) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad size on pointer '%#lx' alloced in '%s:%u'",
- CHUNK_TO_USER(pnt), bblockp->bb_file, bblockp->bb_line);
- malloc_errno = MALLOC_BAD_SIZE;
- _malloc_perror(func);
- return ERROR;
- }
-
- if (min_size != 0 && bblockp->bb_size < min_size) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("not enough space in pointer '%#lx' alloced in '%s:%u'",
- CHUNK_TO_USER(pnt), bblockp->bb_file, bblockp->bb_line);
- malloc_errno = MALLOC_WOULD_OVERWRITE;
- _malloc_perror(func);
- return ERROR;
- }
-
- /* check file pointer */
- if (bblockp->bb_file == NULL) {
- len = strlen(bblockp->bb_file);
- if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad file-name on pointer '%#lx' alloced in '%s:%u'",
- CHUNK_TO_USER(pnt), bblockp->bb_file,
- bblockp->bb_line);
- malloc_errno = MALLOC_BAD_FILEP;
- _malloc_perror(func);
- return ERROR;
- }
- }
-
- /* check out the fence-posts if we are at the start of a user-block */
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)
- && BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
- if (fence_read(bblockp->bb_file, bblockp->bb_line,
- pnt, bblockp->bb_size) != NOERROR)
- return ERROR;
-
- return NOERROR;
- }
-
- /**************************** information routines ***************************/
-
- /*
- * return some information associated with PNT, returns [NO]ERROR
- */
- EXPORT int _chunk_read_info(char * pnt, unsigned int * size,
- char ** file, unsigned int * line)
- {
- bblock_t *bblockp;
- dblock_t *dblockp;
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("reading info about pointer '%#lx'", pnt);
-
- /* adjust the pointer down if fence-posting */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
- pnt -= FENCE_BOTTOM;
-
- /* find which block it is in */
- bblockp = find_bblock(pnt, NULL, NULL);
- if (bblockp == NULL) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", pnt);
- _malloc_perror("find_bblock");
- return ERROR;
- }
-
- /* are we looking in a DBLOCK */
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
- /* on a mini-block boundary? */
- if ((pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc) != 0) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_ON_BLOCK;
- _malloc_perror("_chunk_read_info");
- return ERROR;
- }
-
- /* find correct dblockp */
- dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
- (1 << bblockp->bb_bitc);
-
- if (dblockp->db_bblock == bblockp) {
- /* NOTE: we should run through free list here */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_ALREADY_FREE;
- _malloc_perror("_chunk_read_info");
- return ERROR;
- }
-
- /* write info back to user space */
- if (size != NULL)
- *size = dblockp->db_size;
- if (file != NULL)
- *file = dblockp->db_file;
- if (line != NULL)
- *line = dblockp->db_line;
- }
- else {
-
- /* verify that the pointer is either dblock or user allocated */
- if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_USER;
- _malloc_perror("_chunk_read_info");
- return ERROR;
- }
-
- /* write info back to user space */
- if (size != NULL)
- *size = bblockp->bb_size;
- if (file != NULL)
- *file = bblockp->bb_file;
- if (line != NULL)
- *line = bblockp->bb_line;
- }
-
- return NOERROR;
- }
-
- /*
- * write new FILE, LINE, SIZE info into PNT
- */
- LOCAL int chunk_write_info(const char * file, const unsigned int line,
- char * pnt, unsigned int size)
- {
- int bitc, bblockc;
- bblock_t *bblockp;
- dblock_t *dblockp;
- bblock_adm_t *bblock_admp;
-
- /* find which block it is in */
- bblockp = find_bblock(pnt, NULL, &bblock_admp);
- if (bblockp == NULL) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", pnt);
- _malloc_perror("find_bblock");
- return ERROR;
- }
-
- /* are we looking in a DBLOCK */
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
- /* on a mini-block boundary? */
- if ((pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc) != 0) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_ON_BLOCK;
- _malloc_perror("chunk_write_info");
- return ERROR;
- }
-
- /* find correct dblockp */
- dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
- (1 << bblockp->bb_bitc);
-
- if (dblockp->db_bblock == bblockp) {
- /* NOTE: we should run through free list here */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_USER;
- _malloc_perror("chunk_write_info");
- return ERROR;
- }
-
- /* write info back to user space */
- if (size != NULL)
- dblockp->db_size = size;
- if (file != NULL)
- dblockp->db_file = (char *)file;
- if (line != NULL)
- dblockp->db_line = (unsigned short)line;
- }
- else {
-
- /* verify that the pointer is user allocated */
- if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_USER;
- _malloc_perror("chunk_write_info");
- return ERROR;
- }
-
- /* count the bits */
- bitc = num_bits(bblockp->bb_size);
- if (bitc == ERROR)
- return ERROR;
- if (bitc < BASIC_BLOCK) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad size on pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_BAD_SIZE_INFO;
- _malloc_perror("chunk_write_info");
- return ERROR;
- }
-
- /*
- * reset values in the bblocks
- */
- for (bblockc = 0; bblockc < (1 << (bitc - BASIC_BLOCK));
- bblockc++, bblockp++) {
-
- /* do we need to hop to a new bblock_admp header? */
- if (bblockp == &bblock_admp->ba_block[BB_PER_ADMIN]) {
- bblock_admp = bblock_admp->ba_next;
- if (bblock_admp == NULL) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_BAD_ADMIN_LIST;
- _malloc_perror("chunk_write_info");
- return ERROR;
- }
- bblockp = bblock_admp->ba_block;
- }
-
- /* set bblock info */
- bblockp->bb_size = size;
- bblockp->bb_file = (char *)file;
- bblockp->bb_line = (unsigned short)line;
- }
- }
-
- return NOERROR;
- }
-
- /************************** low-level user functions *************************/
-
- /*
- * get a SIZE chunk of memory for FILE at LINE
- */
- EXPORT char *_chunk_malloc(const char * file, const unsigned int line,
- unsigned int size)
- {
- int bitc, bblockc;
- bblock_t *bblockp;
- bblock_adm_t *bblock_admp;
- dblock_t *dblockp;
- char *mem;
-
- malloc_count++; /* counts calls to malloc */
-
- #if ALLOW_ALLOC_ZERO_SIZE == 0
- if (size == 0) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad zero byte allocation from '%s:%u'", file, line);
- malloc_errno = MALLOC_BAD_SIZE;
- _malloc_perror("_chunk_malloc");
- return MALLOC_ERROR;
- }
- #endif
-
- if (file == NULL) {
- malloc_errno = MALLOC_BAD_FILEP;
- _malloc_perror("_chunk_malloc");
- return MALLOC_ERROR;
- }
-
- /* adjust the size */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
- size += FENCE_OVERHEAD;
-
- /* count the bits */
- bitc = num_bits(size);
- if (bitc == ERROR)
- return MALLOC_ERROR;
-
- /* monitor current allocation level */
- alloc_current += size;
- alloc_cur_given += 1 << bitc;
- alloc_maximum = MAX(alloc_maximum, alloc_current);
- alloc_max_given = MAX(alloc_max_given, alloc_cur_given);
- alloc_total += size;
- alloc_one_max = MAX(alloc_one_max, size);
-
- /* monitor pointer usage */
- alloc_cur_pnts++;
- alloc_max_pnts = MAX(alloc_max_pnts, alloc_cur_pnts);
- alloc_tot_pnts++;
-
- /* have we exceeded the upper bounds */
- if (bitc > LARGEST_BLOCK) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad allocation of '%d' bytes from '%s:%u'",
- size, file, line);
- malloc_errno = MALLOC_TOO_BIG;
- _malloc_perror("_chunk_malloc");
- return MALLOC_ERROR;
- }
-
- /* normalize to SMALLEST_BLOCK. No use spending 16 bytes to admin 1 byte */
- if (bitc < SMALLEST_BLOCK)
- bitc = SMALLEST_BLOCK;
-
- /* allocate divided block if small */
- if (bitc < BASIC_BLOCK) {
- mem = get_dblock(bitc, &dblockp);
- if (mem == NULL)
- return MALLOC_ERROR;
-
- dblockp->db_line = (unsigned short)line;
- dblockp->db_size = (unsigned short)size;
- dblockp->db_file = (char *)file;
- }
- else {
-
- /*
- * allocate some bblock space
- */
-
- /* handle blocks */
- bblockp = get_bblocks(bitc);
- if (bblockp == NULL)
- return MALLOC_ERROR;
-
- /* calculate current bblock admin pointer and memory pointer */
- bblock_admp = (bblock_adm_t *)WHAT_BLOCK(bblockp);
- mem = BLOCK_POINTER(bblock_admp->ba_count +
- (bblockp - bblock_admp->ba_block));
-
- /*
- * initialize the bblocks
- */
- for (bblockc = 0; bblockc < (1 << (bitc - BASIC_BLOCK));
- bblockc++, bblockp++) {
-
- /* do we need to hop to a new bblock admin header? */
- if (bblockp == &bblock_admp->ba_block[BB_PER_ADMIN]) {
- bblock_admp = bblock_admp->ba_next;
- if (bblock_admp == NULL)
- return MALLOC_ERROR;
-
- bblockp = bblock_admp->ba_block;
- }
-
- /* allocate the block if needed */
- if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED))
- if (_heap_alloc(BLOCK_SIZE) == HEAP_ALLOC_ERROR)
- return MALLOC_ERROR;
-
- if (bblockc == 0)
- bblockp->bb_flags = BBLOCK_START_USER;
- else
- bblockp->bb_flags = BBLOCK_USER;
-
- bblockp->bb_line = (unsigned short)line;
- bblockp->bb_size = (unsigned int)size;
- bblockp->bb_file = (char *)file;
- }
- }
-
- /* overwrite to-be-alloced or non-used portion of memory */
- if (BIT_IS_SET(_malloc_debug, DEBUG_ALLOC_BLANK))
- (void)memset(mem, FREE_CHAR, 1 << bitc);
-
- /* write fence post info if needed */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
- fence_write(mem, size);
-
- /* do we need to print transaction info? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
- _malloc_message("*** alloc: at '%s:%u' asking %u bytes (%d bits), "
- "got '%#lx'",
- file, line, size - pnt_total_adm, bitc,
- mem + pnt_below_adm);
-
- return mem + pnt_below_adm;
- }
-
- /*
- * frees PNT from the heap, returns FREE_ERROR or FREE_NOERROR
- */
- EXPORT int _chunk_free(const char * file, const unsigned int line,
- char * pnt)
- {
- int bblockc, bitc;
- bblock_t *bblockp, *first;
- bblock_adm_t *bblock_admp;
- dblock_t *dblockp;
-
- free_count++; /* counts calls to free */
-
- alloc_cur_pnts--;
-
- /* adjust the pointer down if fence-posting */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
- pnt -= FENCE_BOTTOM;
-
- /* find which block it is in */
- bblockp = find_bblock(pnt, NULL, &bblock_admp);
- if (bblockp == NULL) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", pnt);
- _malloc_perror("find_bblock");
- return FREE_ERROR;
- }
-
- /* are we free'ing a dblock entry? */
- if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
-
- /* on a mini-block boundary? */
- if ((pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc) != 0) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_ON_BLOCK;
- _malloc_perror("_chunk_free");
- return FREE_ERROR;
- }
-
- /* find correct dblockp */
- dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
- (1 << bblockp->bb_bitc);
-
- if (dblockp->db_bblock == bblockp) {
- /* NOTE: we should run through free list here */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_ALREADY_FREE;
- _malloc_perror("_chunk_free");
- return FREE_ERROR;
- }
-
- /* do we need to print transaction info? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
- _malloc_message("*** free: at '%s:%u' dblock pnter '%#lx': size %u, "
- "file '%s:%u'",
- file, line, CHUNK_TO_USER(pnt),
- dblockp->db_size - pnt_total_adm,
- dblockp->db_file, dblockp->db_line);
-
- /* check fence-post, probably again */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
- if (fence_read(dblockp->db_file, dblockp->db_line,
- pnt, dblockp->db_size) != NOERROR)
- return FREE_ERROR;
-
- /* count the bits */
- bitc = bblockp->bb_bitc;
-
- /* monitor current allocation level */
- alloc_current -= dblockp->db_size;
- alloc_cur_given -= 1 << bitc;
-
- /* rearrange info */
- dblockp->db_bblock = bblockp;
- dblockp->db_next = free_dblock[bitc];
- free_dblock[bitc] = dblockp;
- free_space_count += 1 << bitc;
-
- /* should we set free memory with FREE_CHAR? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
- (void)memset(pnt, FREE_CHAR, 1 << bitc);
-
- return FREE_NOERROR;
- }
-
- /* on a block boundary? */
- if (! ON_BLOCK(pnt)) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_ON_BLOCK;
- _malloc_perror("_chunk_free");
- return FREE_ERROR;
- }
-
- /* are we on a normal block */
- if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_NOT_START_USER;
- _malloc_perror("_chunk_free");
- return FREE_ERROR;
- }
-
- /* do we need to print transaction info? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
- _malloc_message("*** free: at '%s:%u' bblock pnter '%#lx': size %u, "
- "file '%s:%u'",
- file, line, CHUNK_TO_USER(pnt),
- bblockp->bb_size - pnt_total_adm,
- bblockp->bb_file, bblockp->bb_line);
-
- /* check fence-post, probably again */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
- if (fence_read(bblockp->bb_file, bblockp->bb_line,
- pnt, bblockp->bb_size) != NOERROR)
- return FREE_ERROR;
-
- /* count the bits */
- bitc = num_bits(bblockp->bb_size);
- if (bitc == ERROR)
- return FREE_ERROR;
-
- /* monitor current allocation level */
- alloc_current -= bblockp->bb_size;
- alloc_cur_given -= 1 << bitc;
-
- if (bitc < BASIC_BLOCK) {
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
- _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
- malloc_errno = MALLOC_BAD_SIZE_INFO;
- _malloc_perror("_chunk_free");
- return FREE_ERROR;
- }
-
- /* setup free linked-list */
- first = free_bblock[bitc];
- free_bblock[bitc] = bblockp;
- free_space_count += 1 << bitc;
-
- bblockp->bb_next = first;
-
- /*
- * initialize the bblocks
- */
- for (bblockc = 0; bblockc < (1 << (bitc - BASIC_BLOCK));
- bblockc++, bblockp++, pnt += BLOCK_SIZE) {
-
- /* do we need to hop to a new bblock_admp header? */
- if (bblockp == &bblock_admp->ba_block[BB_PER_ADMIN]) {
- bblock_admp = bblock_admp->ba_next;
- if (bblock_admp == NULL) {
- malloc_errno = MALLOC_BAD_ADMIN_LIST;
- _malloc_perror("_chunk_free");
- return FREE_ERROR;
- }
- bblockp = bblock_admp->ba_block;
- }
-
- /* set bblock info */
- bblockp->bb_flags = BBLOCK_FREE;
- bblockp->bb_bitc = bitc; /* num bblocks in this chunk */
- bblockp->bb_mem = pnt; /* pointer to real memory */
- bblockp->bb_next = first;
-
- /* should we set free memory with FREE_CHAR? */
- if (BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
- (void)memset(pnt, FREE_CHAR, BLOCK_SIZE);
- }
-
- return FREE_NOERROR;
- }
-
- /*
- * reallocate a section of memory
- */
- EXPORT char *_chunk_realloc(const char * file, const unsigned int line,
- char * oldp, unsigned int new_size)
- {
- char *newp, *old_file;
- unsigned int old_size, size, old_line;
- int old_bitc, new_bitc;
-
- realloc_count++; /* counts calls to realloc */
-
- /* get info about old pointer */
- if (_chunk_read_info(oldp, &old_size, &old_file, &old_line) != NOERROR)
- return REALLOC_ERROR;
-
- /* adjust the pointer down if fence-posting */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
- oldp -= FENCE_BOTTOM;
- new_size += FENCE_OVERHEAD;
- }
-
- /* check the fence-posting */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
- if (fence_read(file, line, oldp, old_size) != NOERROR)
- return REALLOC_ERROR;
-
- /* get the old and new bit sizes */
- old_bitc = num_bits(old_size);
- if (old_bitc == ERROR)
- return REALLOC_ERROR;
-
- new_bitc = num_bits(new_size);
- if (new_bitc == ERROR)
- return REALLOC_ERROR;
-
- /* if we are not realloc copying and the size is the same */
- if (BIT_IS_SET(_malloc_debug, DEBUG_REALLOC_COPY) || old_bitc != new_bitc) {
-
- /* readjust info */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
- oldp += FENCE_BOTTOM;
- old_size -= FENCE_OVERHEAD;
- new_size -= FENCE_OVERHEAD;
- }
-
- /* allocate space for new chunk */
- newp = _chunk_malloc(file, line, new_size);
- if (newp == MALLOC_ERROR)
- return REALLOC_ERROR;
-
- /*
- * NOTE: _chunk_malloc() already took care of the fence stuff...
- */
-
- /* copy stuff into new section of memory */
- size = MIN(new_size, old_size);
- if (size > 0)
- bcopy(oldp, newp, size);
-
- /* free old pointer */
- if (_chunk_free(file, line, oldp) != FREE_NOERROR)
- return REALLOC_ERROR;
- }
- else {
- /* monitor current allocation level */
- alloc_current += new_size - old_size;
- alloc_maximum = MAX(alloc_maximum, alloc_current);
- alloc_total += new_size;
- alloc_one_max = MAX(alloc_one_max, new_size);
-
- /* monitor pointer usage */
- alloc_tot_pnts++;
-
- /* reuse the old-pointer */
- newp = oldp;
-
- /* rewrite size information */
- if (chunk_write_info(file, line, newp, new_size) != NOERROR)
- return REALLOC_ERROR;
-
- /* overwrite to-be-alloced or non-used portion of memory */
- if (BIT_IS_SET(_malloc_debug, DEBUG_ALLOC_BLANK)
- && (1 << new_bitc) - old_size > 0)
- (void)memset(newp + old_size, FREE_CHAR, (1 << new_bitc) - old_size);
-
- /* write in fence-post info and adjust new pointer over fence info */
- if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
- fence_write(newp, new_size);
-
- newp += FENCE_BOTTOM;
- oldp += FENCE_BOTTOM;
- old_size -= FENCE_OVERHEAD;
- new_size -= FENCE_OVERHEAD;
- }
- }
-
- /*
- * do we need to print transaction info?
- *
- * NOTE: pointers and sizes here a user-level real
- */
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
- _malloc_message("*** realloc: at '%s:%u' from '%#lx' (%u bytes) "
- "file '%s:%u' to '%#lx' (%u bytes)",
- file, line,
- oldp, old_size, old_file, old_line,
- newp, new_size);
-
- /* newp is already user-level real */
- return newp;
- }
-
- /***************************** diagnostic routines ***************************/
-
- /*
- * log present free and used lists
- */
- EXPORT void _chunk_list_count(void)
- {
- int bitc, count;
- char info[256], tmp[80];
- bblock_t *bblockp;
- dblock_t *dblockp;
-
- /* print header bit-counts */
- info[0] = NULLC;
- for (bitc = SMALLEST_BLOCK; bitc <= LARGEST_BLOCK; bitc++) {
- (void)sprintf(tmp, "%*d", FREE_COLUMN, bitc);
- (void)strcat(info, tmp);
- }
-
- _malloc_message("bits: %s", info);
-
- /* dump the free (and later used) list counts */
- info[0] = NULLC;
- for (bitc = SMALLEST_BLOCK; bitc <= LARGEST_BLOCK; bitc++) {
- if (bitc < BASIC_BLOCK)
- for (count = 0, dblockp = free_dblock[bitc]; dblockp != NULL;
- count++, dblockp = dblockp->db_next);
- else
- for (count = 0, bblockp = free_bblock[bitc]; bblockp != NULL;
- count++, bblockp = bblockp->bb_next);
-
- (void)sprintf(tmp, "%*d", FREE_COLUMN, count);
- (void)strcat(info, tmp);
- }
-
- _malloc_message("free: %s", info);
- }
-
- /*
- * log statistics on the heap
- */
- EXPORT void _chunk_stats(void)
- {
- long overhead;
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("getting chunk statistics");
-
- /* version information */
- _malloc_message("malloc version '%s'", malloc_version);
-
- /* general heap information */
- _malloc_message("heap start %#lx, heap end %#lx, heap size %ld bytes",
- _heap_base, _heap_last, HEAP_SIZE);
-
- /* log user allocation information */
- _malloc_message("alloc calls: malloc %d, realloc %d, calloc %d, free %d",
- malloc_count - _calloc_count, realloc_count, _calloc_count,
- free_count);
-
- _malloc_message("total amount of memory allocated: %ld bytes (%ld pnts)",
- alloc_total, alloc_tot_pnts);
-
- _malloc_message("maximum memory in use at one time: %ld bytes (%ld pnts)",
- alloc_maximum, alloc_max_pnts);
-
- _malloc_message("maximum memory alloced with 1 call: %ld bytes",
- alloc_one_max);
-
- _malloc_message("max base 2 allocation loss: %ld bytes (%d%%)",
- alloc_max_given - alloc_maximum,
- (alloc_max_given == 0 ? 0 :
- 100 - ((alloc_maximum * 100) / alloc_max_given)));
-
- _malloc_message("final user memory space: %ld bytes",
- alloc_current + free_space_count);
-
- /* log administration information */
- _malloc_message("final admin: basic-blocks %d, divided blocks %d",
- bblock_count, dblock_count);
-
- overhead = HEAP_SIZE - (alloc_current + free_space_count);
-
- _malloc_message("final heap admin overhead: %ld bytes (%d%%)",
- overhead,
- (HEAP_SIZE == 0 ? 0 : (overhead * 100) / HEAP_SIZE));
- }
-
- /*
- * dump the unfreed memory, logs the unfreed information to logger
- */
- EXPORT void _chunk_dump_not_freed(void)
- {
- bblock_adm_t *this;
- bblock_t *bblockp;
- dblock_t *dblockp;
- char *mem, unknown;
- int unknown_sizec = 0, unknown_dblockc = 0, unknown_bblockc = 0;
- int sizec = 0, dblockc = 0, bblockc = 0;
-
- if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
- _malloc_message("dumping the unfreed pointers");
-
- /* has anything been alloced yet? */
- this = bblock_adm_head;
- if (this == NULL)
- return;
-
- /* check out the basic blocks */
- for (bblockp = this->ba_block;; bblockp++) {
-
- /* are we at the end of the bb_admin section */
- if (bblockp >= this->ba_block + BB_PER_ADMIN) {
- this = this->ba_next;
-
- /* are we done? */
- if (this == NULL)
- break;
-
- bblockp = this->ba_block;
- }
-
- /*
- * check for different types
- */
- switch (bblockp->bb_flags) {
-
- case BBLOCK_ADMIN:
- case BBLOCK_DBLOCK:
- case BBLOCK_FREE:
- case BBLOCK_USER:
- break;
-
- case BBLOCK_START_USER:
- /* find pointer to memory chunk */
- mem = BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block));
-
- /* unknown pointer? */
- if (bblockp->bb_line == MALLOC_DEFAULT_LINE
- && strcmp(MALLOC_DEFAULT_FILE, bblockp->bb_file) == 0) {
- unknown_bblockc++;
- unknown_sizec += bblockp->bb_size - pnt_total_adm;
- unknown = 1;
- }
- else
- unknown = 0;
-
- if (! unknown || BIT_IS_SET(_malloc_debug, DEBUG_LOG_UNKNOWN))
- _malloc_message("not freed: %#9lx (%8d bytes) from '%s:%u'",
- mem + pnt_below_adm, bblockp->bb_size - pnt_total_adm,
- bblockp->bb_file, bblockp->bb_line);
-
- sizec += bblockp->bb_size - pnt_total_adm;
- bblockc++;
- break;
-
- case BBLOCK_DBLOCK_ADMIN:
-
- for (dblockp = bblockp->bb_slotp->da_block;
- dblockp < bblockp->bb_slotp->da_block + DB_PER_ADMIN; dblockp++) {
-
- /* verify if we have a good bblock pointer and good back pointer */
- if (dblockp->db_bblock == NULL && dblockp->db_next == NULL)
- continue;
-
- /* check out dblock pointer and next pointer (if free) */
- if (dblockp->db_next == NULL || IS_IN_HEAP(dblockp->db_next))
- continue;
-
- {
- bblock_adm_t *bbap;
- bblock_t *bbp;
-
- bbap = bblock_adm_head;
-
- /* check out the basic blocks */
- for (bbp = bbap->ba_block;; bbp++) {
-
- /* are we at the end of the bb_admin section */
- if (bbp >= bbap->ba_block + BB_PER_ADMIN) {
- bbap = bbap->ba_next;
-
- /* are we done? */
- if (bbap == NULL)
- break;
-
- bbp = bbap->ba_block;
- }
-
- if (bbp->bb_flags != BBLOCK_DBLOCK)
- continue;
-
- if (dblockp >= bbp->bb_dblock
- && dblockp < bbp->bb_dblock +
- (1 << (BASIC_BLOCK - bbp->bb_bitc)))
- break;
- }
-
- if (bbap == NULL) {
- malloc_errno = MALLOC_BAD_DBLOCK_POINTER;
- _malloc_perror("_chunk_dump_not_freed");
- return;
- }
-
- mem = bbp->bb_mem + (dblockp - bbp->bb_dblock) * (1 << bbp->bb_bitc);
- }
-
- /* unknown pointer? */
- if (dblockp->db_line == MALLOC_DEFAULT_LINE
- && strcmp(MALLOC_DEFAULT_FILE, dblockp->db_file) == 0) {
- unknown_dblockc++;
- unknown_sizec += dblockp->db_size - pnt_total_adm;
- unknown = 1;
- }
- else
- unknown = 0;
-
- if (! unknown || BIT_IS_SET(_malloc_debug, DEBUG_LOG_UNKNOWN))
- _malloc_message("not freed: %#9lx (%8d bytes) from '%s:%u'",
- mem + pnt_below_adm,
- dblockp->db_size - pnt_total_adm,
- dblockp->db_file, dblockp->db_line);
-
- sizec += dblockp->db_size - pnt_total_adm;
- dblockc++;
- }
- break;
- }
- }
-
- /* copy out size of pointers */
- if (bblockc + dblockc > 0) {
- _malloc_message("known memory not freed: %d bblock, %d dblock, %d byte%s",
- bblockc - unknown_bblockc, dblockc - unknown_dblockc,
- sizec - unknown_sizec, (sizec == 1 ? "" : "s"));
-
- _malloc_message("unknown memory not freed: %d bblock, %d dblock, "
- "%d byte%s",
- unknown_bblockc, unknown_dblockc, unknown_sizec,
- (unknown_sizec == 1 ? "" : "s"));
- }
- }
-
- /*
- * log the heap structure plus information on the blocks if necessary
- */
- EXPORT void _chunk_log_heap_map(void)
- {
- /* did we map the heap second ago? */
- if (! BIT_IS_SET(_malloc_debug, DEBUG_CHECK_HEAP) ||
- ! BIT_IS_SET(_malloc_debug, DEBUG_HEAP_CHECK_MAP))
- log_heap_map();
- }
-